#include "Test.h"

#include "Config.h"
#include <utility>

#include <iostream>
#include <sstream>
#include <fstream>

Test::Test(vector<WordsLine> outputlines ,vector<WordsLine> truthlines, bool matchcontent)
{


  //#test against testlines
  vector<Word> outputwords = collectWords(outputlines);
  vector<Word> truthwords  = collectWords(truthlines);

  d_submitted = outputwords.size();
  d_present   = truthwords.size();


  d_found   = matchAll(truthwords, outputwords, matchcontent); //recal
  d_correct = matchAll(outputwords, truthwords, matchcontent); // precision

  d_recal     = ((double)d_found)   / ((double)d_present);
  d_precision = ((double)d_correct) / ((double)d_submitted);

  d_fscore = (2* d_precision * d_recal ) / (d_precision + d_recal);
}

Test::Test(vector<Test> othertests)
{
  d_submitted = 0;
  d_present   = 0;
  d_found     = 0;
  d_correct   = 0;
  for(unsigned index = 0; index < othertests.size(); index++)
  {
    d_submitted += othertests.at(index).d_submitted;
    d_present   += othertests.at(index).d_present;
    d_found     += othertests.at(index).d_found;
    d_correct   += othertests.at(index).d_correct;
  }



  d_recal     = ((double)d_found)   / ((double)d_present);
  d_precision = ((double)d_correct) / ((double)d_submitted);

  d_fscore = (2* d_precision * d_recal ) / (d_precision + d_recal);
}

int Test::matchAll(vector<Word> allwords1, vector<Word> allwords2, bool matchcontent)
{
  int foundcount = 0;
  for(unsigned wordindex1 = 0; wordindex1 < allwords1.size(); wordindex1++)
     if(contains(allwords1.at(wordindex1), allwords2, matchcontent))
       foundcount++;
  return foundcount;
}

bool Test::contains(Word tocheck, vector<Word> allwords, bool matchcontent)
{
  double best_dist = -1;
  Word   best_word;
  for(unsigned wordindex = 0; wordindex < allwords.size(); wordindex++)
  {
    int dist = computeWordzoneDistance(tocheck, allwords.at(wordindex));
    if(matchcontent)
    {
      if(tocheck.text.compare(allwords.at(wordindex).text) == 0)
      {
        if (best_dist == -1) 
        {
          best_word = allwords.at(wordindex);
          best_dist = dist;      
        }
        if (dist <= best_dist)
        {
          best_word = allwords.at(wordindex);
          best_dist = dist; 
        }
      }
    }
    else
    {
      if (best_dist == -1)
      {
        best_word = allwords.at(wordindex);
        best_dist = dist;      
      }
      if (dist <= best_dist)
      {
        best_word = allwords.at(wordindex);
        best_dist = dist; 
      }
    }
  }

  if(best_dist == -1)
    return false;

  int threshold = Config::getInstance()->thresholddistance;
  //threshold *= threshold;
  if(best_dist >= threshold)
    return false;
  else
    return true;
}

double Test::computeWordzoneDistance(Word word1, Word word2)
{
    // Top
    double d_top    = (word1.top - word2.top)       * (word1.top - word2.top);
    // Bottom
    double d_bottom = (word1.bottom - word2.bottom) * (word1.bottom - word2.bottom);
    // Left
    double word1_lmid = (word1.left + word1.get_lower_left())   / 2.0;
    double word2_lmid = (word2.left + word2.get_lower_left())   / 2.0;
    double d_left   = (word1_lmid - word2_lmid)     * (word1_lmid - word2_lmid);
    // Right
    double word1_rmid = (word1.right + word1.get_lower_right()) / 2.0;
    double word2_rmid = (word2.right + word2.get_lower_right()) / 2.0;
    double d_right = (word1_rmid - word2_rmid)      * (word1_rmid - word2_rmid);
    return (d_top + d_bottom + d_left + d_right) / 4.0;
}


vector<Word> Test::collectWords(vector<WordsLine> lines)
{
    vector<Word> words = vector<Word>();
      for(unsigned lineindex = 0; lineindex < lines.size(); lineindex++)
        for(unsigned wordindex = 0; wordindex < lines.at(lineindex).words.size(); wordindex++)
            words.push_back(lines.at(lineindex).words.at(wordindex));
    return words;
}

void Test::printResults()
{
  //  cout << "Recal          : " << d_found   << " of " << d_present   << " true zones were detected."  << endl;
  //  cout << "Precision      : " << d_correct << " of " << d_submitted << " yielded zones are correct." << endl;
  //  cout << "Recal score    : " << d_recal     << endl;
  //  cout << "Precision score: " << d_precision << endl;
  //  cout << "F-score        : " << d_fscore    << endl;
  cout << getResults();
}

string Test::getResults(){
    stringstream ss;
    ss << "Recal          : " << d_found   << " of " << d_present   << " true zones were detected."  << endl;
    ss << "Precision      : " << d_correct << " of " << d_submitted << " yielded zones are correct." << endl;
    ss << "Recal score    : " << d_recal     << endl;
    ss << "Precision score: " << d_precision << endl;
    ss << "F-score        : " << d_fscore    << endl;
    return ss.str();
}


